package com.xuxk.project.library.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.client.utils.JSONUtils;
import com.google.gson.Gson;
import com.xuxk.project.library.annotation.LibraryLog;
import com.xuxk.project.library.util.HttpContextUtils;
import com.xuxk.project.library.util.IPUtils;
import com.xuxk.project.library.util.RequestUtils;
import com.xuxk.project.library.util.SpelParserUtil;
import com.xuxk.project.util.ElkLog;
import io.micrometer.core.instrument.util.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * @author 许孝康
 * @date 2020/7/30
 * @company 橙云科技有限公司
 */
 @Aspect
 @Component
public class LibraryLogAspect {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    @Value("${spring.application.name}")
    private String applicationName ;

    /**
     * request方式
     */
    private static String REQUEST = "#request";
    private static String PREFIX = "#";
    private static String REGEX = "\\+'_'\\+";

    @Around("@annotation(libraryLog)")
    public Object printLog(ProceedingJoinPoint pjp, LibraryLog libraryLog) throws Throwable {

        long beginTime = System.currentTimeMillis();
        //执行方法
        Object excuteResult = pjp.proceed();
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;

        ElkLog elkLog = new ElkLog();

        String key = libraryLog.key() ;
        Map<String,Object> resultMap = new HashMap<>();
        try {
            Class clazz = pjp.getSourceLocation().getWithinType() ;
            Method method = ((MethodSignature)(pjp.getSignature())).getMethod();
            String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method);
            //默认读取所有参数,除了#request
            if(!libraryLog.readRequest()
                    && StringUtils.isBlank(key)){
                for(int i = 0 ;i< parameterNames.length;i++){
                    String childKey = PREFIX+parameterNames[i].replaceAll("\"","");
                    if(!REQUEST.equals(childKey)){
                        resultMap.put(childKey,getKey(childKey,pjp,parameterNames));
                    }
                }
            }

            //指定读取#request
            if(libraryLog.readRequest()
                    ||( StringUtils.isNotBlank(key) && key.indexOf(REQUEST)!=-1 )  ){

                HttpServletRequest request =  (HttpServletRequest)  getKey(REQUEST,pjp,parameterNames);
                resultMap.put(REQUEST, RequestUtils.getQueryParams(request));
            }

            //指定读取#request之外的参数，将key中存在#request 移除
            key = key.replaceAll(REQUEST+REGEX,"").replaceAll(REGEX+REQUEST,"");
            if(!StringUtils.isBlank(key.trim())){
                String[] keys = key.split(REGEX);
                for(int i = 0;i<keys.length;i++){
                    resultMap.put(keys[i],getKey(keys[i],pjp,parameterNames));
                }
            }

            logger.info(clazz.toString() + "."+pjp.getSignature().getName()+ " ,parameters= "+ JSON.toJSONString(resultMap));

            //获取request
            HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

            //写入日志
            elkLog.setCostTime(time);
            elkLog.setIp(IPUtils.getIpAddr(request));
            elkLog.setEventName(libraryLog.eventName());
            elkLog.setClassForName(clazz.toString() + "."+pjp.getSignature().getName());
            elkLog.setRecordDate(new Date());
            elkLog.setRequestMethod(pjp.getSignature().getName());
            elkLog.setServerName(applicationName);
            elkLog.setReqParam(JSON.toJSONString(resultMap));

            logger.info(elkLog.toString());


        }catch (Exception e){
            e.printStackTrace();
        }
        return excuteResult ;

    }

    private Object getKey(String key, ProceedingJoinPoint pjp,String[] parameterNames) {
//        Method method = ((MethodSignature)(pjp.getSignature())).getMethod();
//        String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method);
        return SpelParserUtil.getKey(key, parameterNames, pjp.getArgs());
    }


}
